package com.duguo.dynamicmvc.factory.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class BeanUtils {

    public static String getGetterName(String fieldName, boolean isBooleanType) {
        if (isBooleanType)
            return "is" + getFirstCharUpperCase(fieldName);
        else
            return "get" + getFirstCharUpperCase(fieldName);
    }

    public static String getSetterName(String fieldName) {
        return "set" + getFirstCharUpperCase(fieldName);
    }

    public static String getFieldName(String fieldAccessor) {
    	if(fieldAccessor.startsWith("set") || fieldAccessor.startsWith("get"))
    		fieldAccessor=fieldAccessor.substring(3);
    	else if (fieldAccessor.startsWith("is")) {
    		fieldAccessor=fieldAccessor.substring(2);
        } else {
            throw new RuntimeException(fieldAccessor+" is not a field accessor");
        }
        return getFirstCharLowerCase(fieldAccessor);
    }

    public static boolean hasField(Object targetBean, String fieldName) {
        String getterName = getGetterName(fieldName, false);
        Method methodToInvoke = findMethodFromObject(targetBean, getterName, 0);
        if (methodToInvoke == null) {
            getterName = getGetterName(fieldName, true);
            methodToInvoke = findMethodFromObject(targetBean, getterName, 0);
            if (methodToInvoke == null) {
                return false;
            }
        }


        String setterName = getSetterName(fieldName);
        methodToInvoke = findMethodFromObject(targetBean, setterName, 1);
        if (methodToInvoke == null) {
            return false;
        }
        return true;
    }

    public static <T> T getFieldValue(Object targetBean, String fieldName, Class<T> returnType) {
        String getterName = getGetterName(fieldName, returnType == Boolean.class);
        return invoteMethod(targetBean, getterName, new Object[0], returnType);
    }

    public static <T> T tryToGetFieldValue(Object targetBean, String fieldName, Class<T> returnType) {
        try{
        	String getterName = getGetterName(fieldName, returnType == Boolean.class);
        	return invoteMethod(targetBean, getterName, new Object[0], returnType);
        }catch(Exception ignore){}
        return null;
    }

    public static void setFieldValue(Object targetBean, String fieldName, Object value) {
        String setterName = getSetterName(fieldName);
        invoteMethod(targetBean, setterName, new Object[]{value}, null);
    }

    public static void setStaticFieldValue(Class targetClass, String fieldName, Object value) {
        for (Field currentField : targetClass.getFields()) {
            if (currentField.getName().equals(fieldName)) {
            	try {
					currentField.set(null, value);
					return;
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
            }
        }
        throw new RuntimeException("No static field "+fieldName+" found for class "+targetClass.getName());
    }

    public static <T> T getStaticFieldValue(Class targetClass, String fieldName,Class<T> returnType) throws IllegalArgumentException, IllegalAccessException {
        for (Field currentField : targetClass.getFields()) {
            if (currentField.getName().equals(fieldName)) {
				return  (T)  currentField.get(null);
            }
        }
        throw new RuntimeException("No static field "+fieldName+" found for class "+targetClass.getName());
    }

    public static Object invoteMethod(Object targetBean, String methodName, Object[] params) {
        return invoteMethod(targetBean, methodName, params, Object.class);
    }

    @SuppressWarnings("unchecked")
    public static <T> T invoteMethod(Object targetBean, String methodName, Object[] params, Class<T> returnType) {
        Method methodToInvoke = findMethodFromObject(targetBean, methodName, params.length);
        if (methodToInvoke != null) {
            return (T) doInvoke(targetBean, params, methodToInvoke);
        }else{
        	throw new RuntimeException("not method "+methodName+" found for class "+targetBean.getClass().getName());
        }
    }
    


    public static String getFirstCharUpperCase(String name) {
    	if (name.length() > 1)
            return name.substring(0,1).toUpperCase()+name.substring(1);
    	else
    		return name.toUpperCase();
    }

    public static String getFirstCharLowerCase(String name) {
        return name.substring(0, 1).toLowerCase() + name.substring(1);
    }

	public static String inspectObject(Object value) {
		StringBuffer stringBuffer=new StringBuffer();
		 inspectObject(stringBuffer,value);
		 return stringBuffer.toString();
	}

	public static void inspectObject(StringBuffer stringBuffer,Object value) {
		if(value!=null && value.getClass().isArray()){
			int length=Array.getLength(value);
			if(length>0){
    			for(int i=0;i<length;i++){
    				if(i!=0)
    					stringBuffer.append(",");
    				stringBuffer.append(Array.get(value,i));	
    			}
			}
		}else{
			stringBuffer.append(value);
		}
	}


    private static Object doInvoke(Object targetBean, Object[] params, Method methodToInvoke) {
        try {
            return methodToInvoke.invoke(targetBean, params);
        } catch (Exception e) {
        	throw new RuntimeException(e);
        }
    }

    private static Method findMethodFromObject(Object targetBean, String methodName, int paramLength) {
        if (targetBean != null) {
            return findMethodFromClass(targetBean.getClass(), methodName, paramLength);
        }
        return null;
    }

    private static Method findMethodFromClass(Class targetClass, String methodName, int paramLength) {
        if (targetClass != null) {
            for (Method currentMethod : targetClass.getMethods()) {
                if (currentMethod.getName().equals(methodName) && currentMethod.getParameterTypes().length == paramLength) {
                    return currentMethod;
                }
            }
        }
        return null;
    }


}
